#pragma once
#include <iostream>
#include <unistd.h>
#include <queue>
namespace BlockQueueModule
{
    static size_t capacity = 10;
    template <typename T>
    class BQqueue
    {
    private:
        // 这里的判断也是对公共资源的访问
        bool isfull() { return _q.size() == _cap; }
        bool isempty() { return _q.empty(); }

    public:
        BQqueue(int cap = capacity)
            : _cap(cap), _cwait(0), _pwait(0)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_consumer, nullptr);
            pthread_cond_init(&_producer, nullptr);
        }
        void Equeue(const T &data)
        {
            pthread_mutex_lock(&_mutex);
            while (isfull())
            {
                std::cout << "生产者在等待" << std::endl;
                _pwait++;
                pthread_cond_wait(&_producer, &_mutex);
                std::cout << "生产者被唤醒" << std::endl;
                _pwait--;
            }
            _q.push(data);
            std::cout << "生产者完成生产:" << data << std::endl;
            pthread_mutex_unlock(&_mutex);
            if (_cwait)
            {
                std::cout << "唤醒消费者" << std::endl;
                pthread_cond_signal(&_consumer);
            }
        }
        void Cqueue(T *data)
        {
            pthread_mutex_lock(&_mutex);
            while (isempty())
            {
                std::cout << "消费者在等待" << std::endl;
                _cwait++;
                pthread_cond_wait(&_consumer, &_mutex);
                std::cout << "消费者被唤醒" << std::endl;
                _cwait--;
            }
            *data = _q.front();
            _q.pop();
            std::cout << "消费者完成消费:" << *data << std::endl;
            pthread_mutex_unlock(&_mutex);
            if (_pwait)
            {
                std::cout << "唤醒生产者" << std::endl;
                pthread_cond_signal(&_producer);
            }
        }
        ~BQqueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_consumer);
            pthread_cond_destroy(&_producer);
        }

    private:
        std::queue<T> _q;
        size_t _cap;
        pthread_mutex_t _mutex;
        pthread_cond_t _consumer;
        pthread_cond_t _producer;
        size_t _cwait;
        size_t _pwait;
    };
}